try {

  var medialib;
  var mquery;
  var albumremote;
  var artistremote;
  var filepath;
  var timeout;
  var onalbumchange;
  var frame;
  var firefoxClassLoaderURL;
  var policy;
  var tracingClassLoaderClass;
  var bootstraped;
  var albumArtClass;
  var traceFlag = true;
 
  var applet = null;
  var currentArtist="";
  var currentAlbum="";
  var downloadImage=false;
  var writeMp3Tag=false;

  var prefs;
  var splitter;
  var box=null;
  var oldframe=null;
  var framebox;
  var removespacer;
  var firefoxClassLoaderPackages;
  var packages;
  var playlist;
  var loaded = false;
  var ViewUtils;
  
  function loadAlbums() {
  
	
    var url;
	var javaInstance
    var album = albumremote.stringValue;
	
	var artist = artistremote.stringValue;
	
	downloadImage = this.prefs.getBoolPref("downloadImages");
    writeMp3Tag =  this.prefs.getBoolPref("writeMp3tag");
	
	
	var doc = frame.contentDocument;
	if (doc.wrappedJSObject) 
		doc = doc.wrappedJSObject;
	
	applet = doc.applets[0];
	
	if (applet == null){
		alert("Applet not loaded. Please ensure that java 1.6 (1.5 for Mac OS) is installed on Songbird");
	} else	{
		
		if (((currentAlbum != album) || (currentArtist != artist)) && (album!="" || artist!=""))
		{
			
			currentAlbum = album;
			currentArtist = artist;
			
		}
		
		var file = filepath.stringValue;
			
			
			applet.setDownloadImage(downloadImage);
			applet.setWriteMP3Tag(writeMp3Tag);
			addAlbumsByArtist();
			
		applet.loadingDone();
		
	}	
	
	
		
    
	
	
    
  }
  var filterListenerOfDoom = {
       onSearchChanged: function(changedView)
       {
           var set = new java.util.HashSet();
           alert("search changed");
           for (var i = 0; i < changedView.length; i++ )
           {    
              var item =changedView.getItemByIndex(i);
              set.add(item.getProperty(SBProperties.artistName)+item.getProperty(SBProperties.albumName));
           }
           applet.changeFilter(set);
           
               
       },
       onFilterChanged: function(changedView)
       {
           alert("filter changed");
       },
       onSortChanged: function(changedView)
       {
           
       }
  }
  function initAlbumApplet() {
    initmedialib();
	
	givePermission();
	
    
    albumremote = SB_NewDataRemote("metadata.album", null);
	artistremote = SB_NewDataRemote("metadata.artist", null);
	filepath = SB_NewDataRemote("metadata.url",null);
	/*
   function onPlaylistCellClick( aEvent ) {
   // we can get the property that was clicked on...
     alert(aEvent.property);
     
     // or the <MediaItem>
     alert(aEvent.item.guid);
    
    // as well as key states from MouseEvent
     alert(aEvent.ctrlKey);
   }
	songbird;
	*/
	var albumExtension = {
		albumListener: function(evt) {
				
			   setAlbumFilter(evt.target.getAttribute("album")); 
			  
		}
	}
	
	var loadedExtension = {
		loadedListener: function(evt) {
				
				loadAlbums();           
		}
	}
	
	var playExtension = {
		playListener :  function(evt) {
			setAlbumFilter(evt.target.getAttribute("album"));
			playFilter();
		}
	}
	
        
	var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                  .getInterface(Components.interfaces.nsIWebNavigation)
                  .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
                  .rootTreeItem
                  .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                  .getInterface(Components.interfaces.nsIDOMWindow);
	mainWindow.document.addEventListener("albumChangeEvent", function(e) { albumExtension.albumListener(e); }, false, true);
	mainWindow.document.addEventListener("appletLoadedEvent", function(e) { loadedExtension.loadedListener(e); }, false, true);
	mainWindow.document.addEventListener("AlbumAppletPlayEvent", function(e) { playExtension.playListener(e); }, false, true);
	//mainWindow.document.addEventListener("PlaylistCellClick", onPlaylistCellClick, false, true);
	var onalbumchange = { 
	    observe: function( aSubject, aTopic, aData ) {
        syncSelectedAlbum();
      } 
    };
    albumremote.bindObserver(onalbumchange, true);
	
	
	
	
	var firefoxClassLoaderURL = 
        new java.net.URL(getPath("albumapplet") + "components/firefoxClassLoader.jar");
    
    
	
	
	var extensionPath = getPath("albumapplet");
        
              
        
        /*
         *  Enumerate URLs to our JARs and class directories
         */
		 
        var libPath = extensionPath + "components/lib/";
        var jarFilenames = [
			"classes/",
            "albumjava/", //the albumJava classes,
			"albumjava/ascrblr-1.0-alpha2.jar",
			"albumjava/jdom.jar",
			"albumjava/swingx-2007_10_14.jar",
			"albumjava/sqlitejdbc-v051.jar",
			"albumjava/JID3.jar",
			"albumjava/TimingFramework-1.0.jar"
			
        ];
        
        var jarFilepaths = [];
        for (var i = 0; i < jarFilenames.length; i++) {
            jarFilepaths.push(libPath + jarFilenames[i]);
        }
        
        /*
         *  Load them up!
         */
        packages = loadJava(jarFilepaths);
        
        
        
        
        /*
         *  Create a sample Java object
         */
       
		placeApplet();
		ViewUtils = window.mediaPage;
		
	var mediaListView = ViewUtils.mediaListView;
        mediaListView.addListener(filterListenerOfDoom);
        
		  
		
		
    
    
  }
  
	function syncSelectedAlbum()
	{
		var album = albumremote.stringValue;
		
		var artist = artistremote.stringValue;
		if (((currentAlbum != album) || (currentArtist != artist)) && (album!="" || artist!="") && applet!=null)
		{
			applet.setSelectedAlbum(album,artist);
			
		}
	}
   
	
	
	function setAlbumFilter( aAlbum ) {
		
		try {
		  // Crack out the variables we'll need
		 
		  var mediaListView = ViewUtils.mediaListView;
		  
		  var filters = mediaListView.cascadeFilterSet;
		  
			  for (var i = filters.length - 1; i > 0; i--) {
			filters.remove(i);
		  }
		  
			 filters.appendFilter(SBProperties.albumName);
		  
		  filters.set(0,[aAlbum],1)
		//cascadeFilterSet.appendSearch([SBProperties.albumName], 1);
		//cascadeFilterSet.appendFilter(SBProperties.albumName);
		//cascadeFilterSet.set(0, [aAlbum], 1);
		/*
		  // Find which filter index is the album filter
		  var albumIndex = -1;
		  for ( albumIndex = 0; albumIndex < cascadeFilterSet.length; albumIndex++ ) {
			alert(cascadeFilterSet.getProperty( albumIndex ))
			if ( cascadeFilterSet.getProperty( albumIndex ) == SBProperties.albumName )
			  break;
		  }
		  // If we found the albumIndex
		  if ( albumIndex < cascadeFilterSet.length ) {
			// Get all the valid albums
			var albums = cascadeFilterSet.getValues( albumIndex );
			// Find the requested album
			while ( albums.hasMore() ) {
			  var album = albums.getNext();
			  if ( album == aAlbum ) {
				// And set a single filter value and return
				cascadeFilterSet.set( albumIndex, [ aAlbum ], 1 );
				
				return;
			  }
			}
			// OTHERWISE, I guess you meant to clear the filter, right?
			cascadeFilterSet.set( albumIndex, [ ], 0 );
		  }
		  else {
			alert("Album not found?? " + aAlbum + " " + cascadeFilterSet.length)
			}*/
		} catch ( err ) {
		  alert( "setAlbumFilter( '" + aAlbum + "' )\n\n" + err );
		}
	}
	
	function playFilter(){
		try {
			 var playlist = ViewUtils.playlist;
			 playlist.sendPlayEvent();
		} catch( err) {
			alert("playFilter error. Someone messed up. I swear, it wasn't me! \n" + err);
		}
	}
		
		
	

  function resetalbumArt() {
    
    medialib = null;
    mquery = null;
    albumremote.unbind();
    albumremote = null;
    onalbumchange = null;
	button = null;
  }

  function initmedialib() {
    //medialib = Components.classes["@songbirdnest.com/Songbird/MediaLibrary;1"].createInstance(Components.interfaces.sbILibrary);
    mquery = Components.classes["@songbirdnest.com/Songbird/DatabaseQuery;1"].createInstance(Components.interfaces.sbIDatabaseQuery);
    mquery.setDatabaseGUID("main@library.songbirdnest.com"); 
    //medialib.setQueryObject(mquery);
	prefs = Components.classes["@mozilla.org/preferences-service;1"]
			 .getService(Components.interfaces.nsIPrefService)
			 .getBranch("albumapplet.");
		prefs.QueryInterface(Components.interfaces.nsIPrefBranch2);
  }
  
  function placeApplet() { //places the applet in the interface
	var boxstring;
	var oldframestring;
	
	if (box != null)
	{
		try{
			box.removeChild(framebox);
			box.removeChild(splitter);
			}
		catch (e){}
			
	}

	
	framebox = document.createElement("hbox");
	framebox.setAttribute("flex","1");
	framebox.setAttribute("align","top");
	framebox.setAttribute("id","appletbox");
	//framebox.setAttribute("onclick","getAlbum();");
	
	
	frame = document.createElement("iframe");
	
   frame.setAttribute("flex","1");
   frame.setAttribute("id","flowapplet");
   frame.setAttribute("min-height","10");
   frame.setAttribute("height","1000");
   frame.setAttribute("src",getPath("albumapplet") + "components/lib/albumjava/album.htm");
   frame.setAttribute("mayscript","yes");
   
  
   
	framebox.appendChild(frame);
	splitter = document.createElement("sb-smart-splitter");
	
	splitter.setAttribute("id","horz_splitter");
	splitter.setAttribute("state", "open");
    splitter.setAttribute("resizebefore", "closest");
    splitter.setAttribute("resizeafter", "closest");
    splitter.setAttribute("collapse", "before");
	var grippy = document.createElement( "grippy" );
    splitter.appendChild(grippy);
	

	box=document.getElementById("sb-playlist");
	oldframe = document.getElementById("sb-playlist-filters");
	
	
	box.insertBefore(framebox,oldframe);
	box.insertBefore(splitter,oldframe);
	
	
	
	}

	function getAlbum()
	{
		try{
			applet= frame.contentDocument.applets[0];
			alert(applet.getCurrentAlbum());
		}
		catch(e){}
	}
		
  

  function onalbumChange() {
    loadalbum();
  }
  
  function addAlbumsByArtist()
  {
		/*
		//Remove
		var statusDataRemote;
		var faceplateReg;
		var faceplatePane;
		// Make sure we have the javascript modules we're going to use
		if (!window.SBProperties) 
		  Cu.import("resource://app/jsmodules/sbProperties.jsm");
		if (!window.LibraryUtils) 
		  Cu.import("resource://app/jsmodules/sbLibraryUtils.jsm");

		var list = LibraryUtils.mainLibrary;

		//  Create an enumeration listener to count each item
		var listener = {
		  mediaItem:null,
		  onEnumerationBegin: function(aMediaList) { 
			this.mediaItem = null;
		  },
		  onEnumeratedItem: function(aMediaList, aMediaItem) {
			this.mediaItem = aMediaItem;
		  },
		  onEnumerationEnd: function(aMediaList, aStatusCode) {}
		};

		var artistCounts = {};
		var albums = list.getDistinctValuesForProperty(SBProperties.albumName);
		
		
		var album;
		var  i = 0;
		while(albums.hasMore()) {
			albums.getNext();
			i++;
		}
		albums = list.getDistinctValuesForProperty(SBProperties.albumName);
		applet.setAlbumCount(i);
		// Count the number of media items for each distinct artist
		while (albums.hasMore()) {
			album = albums.getNext();
			list.enumerateItemsByProperty(SBProperties.albumName,
										album,
										listener,
										Ci.sbIMediaList.ENUMERATIONTYPE_LOCKING);
			aMediaItem =listener.mediaItem;
			artist = aMediaItem.getProperty(SBProperties.artistName);
			itemURL = aMediaItem.getProperty(SBProperties.contentURL);
			applet.addImage(itemURL,artist,album);
		  
		}
		*/
		//Remove
		var statusDataRemote;
		var faceplateReg;
		var faceplatePane;

		statusDataRemote = Components.
							  classes["@songbirdnest.com/Songbird/DataRemote;1"].
							  createInstance(Components.interfaces.sbIDataRemote);
		statusDataRemote.init("faceplate.status.text", null);
		//End Remove
		mquery.resetQuery();
		mquery.addQuery("SELECT DISTINCT r1.obj AS album,r2.obj AS artist, r1.content_url AS file FROM (media_items NATURAL JOIN  resource_properties) AS r1, resource_properties AS r2  WHERE r1.property_id=2 AND r2.property_id=3 AND r1.media_item_id=r2.media_item_id  GROUP BY album ORDER BY r2.obj ");
		mquery.execute();
		mquery.waitForCompletion();
		var albums = mquery.getResultObject();
		var count = albums.getRowCount();
		var index
		var artist;
		dump("Calling applet");
		applet.setAlbumCount(count);
		for( var i = 0; i<count; i++)
		{
			applet.addImage(albums.getRowCellByColumn(i,"file"),albums.getRowCellByColumn(i,"artist"),albums.getRowCellByColumn(i,"album"));
		}
	
	

	
	}
	
	function getPath(extensionName) {
		var chromeRegistry =
		Components.classes["@mozilla.org/chrome/chrome-registry;1"]
		.getService(Components.interfaces.nsIChromeRegistry);

		var uri =
		Components.classes["@mozilla.org/network/standard-url;1"]
		.createInstance(Components.interfaces.nsIURI);

		uri.spec = "chrome://" + extensionName + "/content/";

		var path = chromeRegistry.convertChromeURL(uri);
		if (typeof(path) == "object") {
		path = path.spec;
		}

		path = path.substring(0, path.indexOf("/chrome/") + 1);

		return path;
	}
	
	function givePermission()
	{
		firefoxClassLoaderURL = 
		new java.net.URL(getPath("albumapplet") + "components/firefoxClassLoader.jar");
		
		loaderURLs = java.lang.reflect.Array.newInstance(java.net.URL, 1);
		loaderURLs[0] = firefoxClassLoaderURL;

		/*
		 *  Step 1. Load the bootstraping firefoxClassLoader.jar.
		 */
		var bootstrapClassLoader = java.net.URLClassLoader.newInstance(loaderURLs);
		
		/*
		 *  Step 2. Instantiate a URLSetPolicy object from firefoxClassLoader.jar.
		 */
		var policyClass = java.lang.Class.forName(
			"edu.mit.simile.firefoxClassLoader.URLSetPolicy",
			true,
			bootstrapClassLoader
		);
		policy = policyClass.newInstance();
		
		/*
		 *  Step 3. Now, the trick: We wrap our own URLSetPolicy around
		 *  the current security policy of the JVM security manager. This
		 *  allows us to give our own Java code whatever permission we
		 *  want, even though Firefox doesn't give us any permission.
		 */
		policy.setOuterPolicy(java.security.Policy.getPolicy());
		java.security.Policy.setPolicy(policy);
		
		/*
		 *  Step 4. Give ourselves all permission. Yay!
		 */
		policy.addPermission(new java.security.AllPermission());
			
		/*
		 *  That's pretty much it for the security bootstraping hack. But we want to
		 *  do a little more. We want our own class loader for subsequent JARs that
		 *  we load.
		 */
		 
		/*
		 *  Step 5. Reload firefoxClassLoader.jar and so we can make use of
		 *  TracingClassLoader. We need to reload it because when it was
		 *  loaded previously, we had not yet set the policy to give it
		 *  enough permission for loading classes.
		 */
		  
		policy.addURL(firefoxClassLoaderURL);
		
		firefoxClassLoaderPackages = new WrappedPackages(
			java,
			java.net.URLClassLoader.newInstance(loaderURLs)
		);
		tracingClassLoaderClass = 
			firefoxClassLoaderPackages.getClass("edu.mit.simile.firefoxClassLoader.TracingClassLoader");
		bootstraped = true;
		dump("Permissions succesfully given");

	}

	function loadJava(jarURLStrings)
	{
		var jarURLs = [];
		
		/*
		 *  We include the firefoxClassLoader.jar again whenever we
		 *  load more JARs so that we can use various reflection
		 *  utility classes in firefoxClassLoader.jar on these
		 *  JARs.
		 */
		 jarURLs.push(firefoxClassLoaderURL);
		 policy.addURL(jarURLs[0]);
		
		/*
		 *  Now we add the rest of the JARs.
		 */
		for (var i = 0; i < jarURLStrings.length; i++) {
			var jarURL = new java.net.URL(jarURLStrings[i]);
			jarURLs.push(jarURL);
			
			policy.addURL(jarURL); // include the URL in the policy
		}
			
		/*
		 *  Create a new TracingClassLoader
		 */
		var classLoader = tracingClassLoaderClass.m("newInstance")(traceFlag);
		
		/*
		 *  Give it the JARS
		 */
		for (var i = 0; i < jarURLs.length; i++) {
			classLoader.add(jarURLs[i]);
		}
		java.lang.Thread.currentThread().setContextClassLoader(classLoader);
		
		/*
		 *  Wrap up the class loader and return
		 */
		var packages = new WrappedPackages(java, classLoader);
		
		return packages;
	}

	function WrappedPackages(java, classLoader) {
		var packages = java.lang.Class.forName(
			"edu.mit.simile.firefoxClassLoader.Packages",
			true,
			classLoader
		).newInstance();
		
		var argumentsToArray = function(args) {
			var a = [];
			for (var i = 0; i < args.length; i++) {
				a[i] = args[i];
			}
			return a;
		}

		this.getClass = function(className) {
			var classWrapper = packages.getClass(className);
			if (classWrapper) {
				return {
					n : function() {
						return classWrapper.callConstructor(argumentsToArray(arguments));
					},
					f : function(fieldName) {
						return classWrapper.getField(fieldName);
					},
					m : function(methodName) {
						return function() {
							return classWrapper.callMethod(methodName, argumentsToArray(arguments));
						};
					}
				};
			} else {
				return null;
			}
		};
		
		this.setTracing = function(enable) {
			classLoader.setTracing((enable) ? true : false);
		};
	}
		
	
  


	var prefWatcher = {
	   pref: null,
	      
	   // Initialize the extension
	   
	   startup: function()
	   {
		 // Register to receive notifications of preference changes
		 
		 this.pref = Components.classes["@mozilla.org/preferences-service;1"]
			 .getService(Components.interfaces.nsIPrefService)
			 .getBranch("albumapplet.appletPlacement");
		 this.pref.QueryInterface(Components.interfaces.nsIPrefBranch2);
		 this.pref.addObserver("", this, false);
		 
		 
		 
	   },
	   observe: function(subject, topic, data)
	   {
		 if (topic != "nsPref:changed")
		 {
		   return;
		 }
	 
		 placeApplet();
	   },
	   
	   shutdown: function()
	  {
		this.pref.removeObserver("", this);
	  }
	}
	prefWatcher.startup();
} catch (e) {
}
   
